<template>
  <h1>{{ msg }}</h1>
  <button @click="count++">count is: {{ count }}</button>
  <p>{{ counter }}</p>
  <p>{{ doubleCounter }}</p>
  <button @click="clearTimer">暂停计时器</button>
  <p ref="tagP">11</p>
  <ModelButton></ModelButton>
  <Emits @my-click="myClick"></Emits>
  <myDiv title="引入标题"></myDiv>

  <myDiv2></myDiv2>
  <!-- vue3.0写法 -->
  <ModelTest v-model="modelcounter"></ModelTest>

  <!-- 等效于vue2.0写法 -->
  <!-- <ModelTest :conten="modelcounter" @update:conten="modelcounter = $event"></ModelTest> -->

  <!-- 使用render自定义渲染函数，slot的用法 -->
  <RenderTest v-model:renderMsg="modelcounter">
    <template v-slot:header>
      <div>具名插槽 slots.header() 获取值</div>
    </template>
  </RenderTest>

  <!-- 函数式组件的声明方式 -->
  <Functional :level="modelcounter">动态h元素</Functional>

  <!-- 异步组件 -->
  <AsyncPage></AsyncPage>

  <!-- 使用全局自定义指令 -->
  <h3 v-bgColor="'red'">使用自定义指令</h3>

  <!-- 内部自定义命令 -->
  <div v-test="'30px'">组件内部自定义命令</div>

  <!-- 全局自定义命令和内部自定义命令同时使用 -->
  <b v-bgColor="'green'" v-test="'30px'">使用自定义指令</b>

  <!-- 动画 -->
  <TransitionTest></TransitionTest>

  <!-- keyCode别名修饰符 -->
  <input type="text" v-model="inputText" v-on:keyup.enter="alertInputText" />

  <!-- 使用mitt派发事件 -->
  <button @click="mittEmit">派发事件</button>
</template>

<script>
import {
  computed,
  onMounted,
  onUnmounted,
  reactive,
  ref,
  toRefs,
  watch,
  nextTick,
  h,
  defineAsyncComponent,
} from "vue";
import ModelButton from "./ModelButton.vue";
import Emits from "./Emits.vue";
import ModelTest from "./ModelTest.vue";
import Functional from "./Functional.vue";
import TransitionTest from "./TransitionTest.vue";

import emitter from "../util/mitt.js";

export default {
  props: ["msg"],
  components: {
    ModelButton: ModelButton,
    Emits: Emits,
    ModelTest: ModelTest,
    Functional: Functional,
    RenderTest: {
      props: ["renderMsg"],
      // setup 的第二个参数可以解构为 emit slots attrs
      setup(props, { emit, slots }) {
        // 更新父组件值的方法
        const changePros = () => {
          emit("update:renderMsg", props.renderMsg + 1);
        };
        // 获取插槽
        const headerSlot = slots.header();
        return {
          changePros,
          headerSlot,
        };
      },
      render(ctx) {
        const renderMsg = this.renderMsg;
        return h("div", [
          h(
            "div",
            {
              onClick: ctx.changePros,
            },
            `点我++ ： ${renderMsg}`,
            // this.$slots.header(),
            // 等同于以上写法
            ctx.headerSlot
          ),
        ]);
      },
    },
    AsyncPage: defineAsyncComponent(() => import("./NextPage.vue")),
    TransitionTest: TransitionTest,
  },
  directives: {
    test: {
      beforeMount(el, binding) {
        el.style.fontSize = binding.value;
      },
    },
  },
  setup() {
    // ref 只能声明普通值类型
    const count = ref(0);

    // 声明定时器
    let timer = ref(null);

    // 解构 toRefs 后的数据不会丢失响应式
    const { counter, doubleCounter } = useCounter(timer);

    // 获取元素
    const tagP = useTagp(counter);

    // 暂停方法
    const clearTimer = () => {
      useClearTime(timer);
    };

    // 子组件调用父组件方法
    const myClick = (propsMsg) => {
      myClickFn(propsMsg);
    };

    // vue3.0的写法
    nextTick(() => {
      console.log("页面加载后触发");
    });

    // 给组件绑定值，在组件内部更改这个值
    let modelcounter = ref(1);

    // 输入框绑定值
    let inputText = ref("");

    // 输入框回车事件
    const alertInputText = () => {
      alert(inputText.value);
    };

    // 派发事件
    const mittEmit = () => {
      emitter.emit("helloPageEmitFun", inputText.value);
    };
       
    return {
      count,
      counter,
      doubleCounter,
      clearTimer,
      tagP,
      myClick,
      modelcounter,
      inputText,
      alertInputText,
      mittEmit,
    };
  },
};

// 计算属性
function useCounter(timer) {
  // reactive 声明引用类型
  const data = reactive({
    counter: 1,
    doubleCounter: computed(() => data.counter * 2),
  });

  // 页面加载触发
  onMounted(() => {
    timer.value = setInterval(() => {
      data.counter++;
    }, 1000);
  });

  // 页面销毁
  onUnmounted(() => {
    clearInterval(timer.value);
  });

  // 使用 toRefs 可以将 reactive 类型 装换为 ref 单个值类型，并且解构不会丢失响应式
  return toRefs(data);
}

// 获取页面元素并且改变值
function useTagp(counter) {
  const tagP = ref(null);
  watch(counter, (val, oldVal) => {
    tagP.value.innerHTML = `from ${oldVal} to ${val}`;
  });
  return tagP;
}

// 清除定时器
function useClearTime(timer) {
  clearInterval(timer.value);
}

// 子组件调用父组件方法
function myClickFn(propsMsg) {
  console.log("来自父组件：Emit。 调用," + propsMsg);
}
</script>
